home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / amiga / plotting / gnuplot3.lzh / gnuplot / scanner.c < prev    next >
C/C++ Source or Header  |  1991-09-05  |  9KB  |  344 lines

  1. /* GNUPLOT - scanner.c */
  2. /*
  3.  * Copyright (C) 1986, 1987, 1990, 1991   Thomas Williams, Colin Kelley
  4.  *
  5.  * Permission to use, copy, and distribute this software and its
  6.  * documentation for any purpose with or without fee is hereby granted, 
  7.  * provided that the above copyright notice appear in all copies and 
  8.  * that both that copyright notice and this permission notice appear 
  9.  * in supporting documentation.
  10.  *
  11.  * Permission to modify the software is granted, but not the right to
  12.  * distribute the modified code.  Modifications are to be distributed 
  13.  * as patches to released version.
  14.  *  
  15.  * This software is provided "as is" without express or implied warranty.
  16.  * 
  17.  *
  18.  * AUTHORS
  19.  * 
  20.  *   Original Software:
  21.  *     Thomas Williams,  Colin Kelley.
  22.  * 
  23.  *   Gnuplot 2.0 additions:
  24.  *       Russell Lang, Dave Kotz, John Campbell.
  25.  *
  26.  *   Gnuplot 3.0 additions:
  27.  *       Gershon Elber and many others.
  28.  * 
  29.  * Send your comments or suggestions to 
  30.  *  pixar!info-gnuplot@sun.com.
  31.  * This is a mailing list; to join it send a note to 
  32.  *  pixar!info-gnuplot-request@sun.com.  
  33.  * Send bug reports to
  34.  *  pixar!bug-gnuplot@sun.com.
  35.  */
  36.  
  37. #include <stdio.h>
  38. #include <ctype.h>
  39. #include "plot.h"
  40.  
  41. #ifdef AMIGA_AC_5
  42. #define O_RDONLY    0
  43. int open(const char * _name, int _mode, ...);
  44. int close(int);
  45. #endif
  46.  
  47. #ifdef vms
  48.  
  49. #include stdio
  50. #include descrip
  51. #include errno
  52.  
  53. #define MAILBOX "PLOT$MAILBOX"
  54. #define pclose(f) fclose(f)
  55.  
  56. #endif /* vms */
  57.  
  58.  
  59. #define isident(c) (isalnum(c) || (c) == '_')
  60.  
  61. #ifndef STDOUT
  62. #define STDOUT 1
  63. #endif
  64.  
  65. #define LBRACE '{'
  66. #define RBRACE '}'
  67.  
  68. #define APPEND_TOKEN {token[t_num].length++; current++;}
  69.  
  70. #define SCAN_IDENTIFIER while (isident(expression[current + 1]))\
  71.                 APPEND_TOKEN
  72.  
  73. extern struct lexical_unit token[MAX_TOKENS];
  74.  
  75. static int t_num;    /* number of token I'm working on */
  76.  
  77. char *strcat(), *strcpy(), *strncpy();
  78.  
  79. /*
  80.  * scanner() breaks expression[] into lexical units, storing them in token[].
  81.  *   The total number of tokens found is returned as the function value.
  82.  *   Scanning will stop when '\0' is found in expression[], or when token[]
  83.  *     is full.
  84.  *
  85.  *     Scanning is performed by following rules:
  86.  *
  87.  *        Current char    token should contain
  88.  *     -------------    -----------------------
  89.  *        1.  alpha        all following alpha-numerics
  90.  *        2.  digit        0 or more following digits, 0 or 1 decimal point,
  91.  *                          0 or more digits, 0 or 1 'e' or 'E',
  92.  *                          0 or more digits.
  93.  *        3.  ^,+,-,/        only current char
  94.  *            %,~,(,)
  95.  *            [,],;,:,
  96.  *            ?,comma
  97.  *        4.  &,|,=,*        current char; also next if next is same
  98.  *        5.  !,<,>        current char; also next if next is =
  99.  *        6.  ", '        all chars up until matching quote
  100.  *        7.  #          this token cuts off scanning of the line (DFK).
  101.  *
  102.  *        white space between tokens is ignored
  103.  */
  104. scanner(expression)
  105. char expression[];
  106. {
  107. register int current;    /* index of current char in expression[] */
  108. register int quote;
  109. char brace;
  110.  
  111.     for (current = t_num = 0;
  112.         t_num < MAX_TOKENS && expression[current] != '\0';
  113.         current++) {
  114. again:
  115.         if (isspace(expression[current]))
  116.             continue;                        /* skip the whitespace */
  117.         token[t_num].start_index = current;
  118.         token[t_num].length = 1;
  119.         token[t_num].is_token = TRUE;    /* to start with...*/
  120.  
  121.         if (expression[current] == '`') {
  122.             substitute(&expression[current],MAX_LINE_LEN - current);
  123.             goto again;
  124.         }
  125.         if (isalpha(expression[current])) {
  126.             SCAN_IDENTIFIER;
  127.         } else if (isdigit(expression[current]) || expression[current] == '.'){
  128.             token[t_num].is_token = FALSE;
  129.             token[t_num].length = get_num(&expression[current]);
  130.             current += (token[t_num].length - 1);
  131.         } else if (expression[current] == LBRACE) {
  132.             token[t_num].is_token = FALSE;
  133.             token[t_num].l_val.type = CMPLX;
  134.             if ((sscanf(&expression[++current],"%lf , %lf %c",
  135.                 &token[t_num].l_val.v.cmplx_val.real,
  136.                 &token[t_num].l_val.v.cmplx_val.imag,
  137.                 &brace) != 3) || (brace != RBRACE))
  138.                     int_error("invalid complex constant",t_num);
  139.             token[t_num].length += 2;
  140.             while (expression[++current] != RBRACE) {
  141.                 token[t_num].length++;
  142.                 if (expression[current] == '\0')            /* { for vi % */
  143.                     int_error("no matching '}'", t_num);
  144.             }
  145.         } else if (expression[current] == '\'' || expression[current] == '\"'){
  146.             token[t_num].length++;
  147.             quote = expression[current];
  148.             while (expression[++current] != quote) {
  149.                 if (!expression[current]) {
  150.                     expression[current] = quote;
  151.                     expression[current+1] = '\0';
  152.                     break;
  153.                 } else
  154.                     token[t_num].length++;
  155.             }
  156.         } else switch (expression[current]) {
  157.              case '#':        /* DFK: add comments to gnuplot */
  158.                   goto endline; /* ignore the rest of the line */
  159.             case '^':
  160.             case '+':
  161.             case '-':
  162.             case '/':
  163.             case '%':
  164.             case '~':
  165.             case '(':
  166.             case ')':
  167.             case '[':
  168.             case ']':
  169.             case ';':
  170.             case ':':
  171.             case '?':
  172.             case ',':
  173.                 break;
  174.             case '&':
  175.             case '|':
  176.             case '=':
  177.             case '*':
  178.                 if (expression[current] == expression[current + 1])
  179.                     APPEND_TOKEN;
  180.                 break;
  181.             case '!':
  182.             case '<':
  183.             case '>':
  184.                 if (expression[current + 1] == '=')
  185.                     APPEND_TOKEN;
  186.                 break;
  187.             default:
  188.                 int_error("invalid character",t_num);
  189.             }
  190.         ++t_num;    /* next token if not white space */
  191.     }
  192.  
  193. endline:                    /* comments jump here to ignore line */
  194.  
  195. /* Now kludge an extra token which points to '\0' at end of expression[].
  196.    This is useful so printerror() looks nice even if we've fallen off the
  197.    line. */
  198.  
  199.         token[t_num].start_index = current;
  200.         token[t_num].length = 0;
  201.     return(t_num);
  202. }
  203.  
  204.  
  205. get_num(str)
  206. char str[];
  207. {
  208. double atof();
  209. register int count = 0;
  210. long atol();
  211. register long lval;
  212.  
  213.     token[t_num].is_token = FALSE;
  214.     token[t_num].l_val.type = INT;        /* assume unless . or E found */
  215.     while (isdigit(str[count]))
  216.         count++;
  217.     if (str[count] == '.') {
  218.         token[t_num].l_val.type = CMPLX;
  219.         while (isdigit(str[++count]))    /* swallow up digits until non-digit */
  220.             ;
  221.         /* now str[count] is other than a digit */
  222.     }
  223.     if (str[count] == 'e' || str[count] == 'E') {
  224.         token[t_num].l_val.type = CMPLX;
  225. /* modified if statement to allow + sign in exponent
  226.    rjl 26 July 1988 */
  227.         count++;
  228.         if (str[count] == '-' || str[count] == '+')
  229.             count++;
  230.         if (!isdigit(str[count])) {
  231.             token[t_num].start_index += count;
  232.             int_error("expecting exponent",t_num);
  233.         }
  234.         while (isdigit(str[++count]))
  235.             ;
  236.     }
  237.     if (token[t_num].l_val.type == INT) {
  238.          lval = atol(str);
  239.         if ((token[t_num].l_val.v.int_val = lval) != lval)
  240.             int_error("integer overflow; change to floating point",t_num);
  241.     } else {
  242.         token[t_num].l_val.v.cmplx_val.imag = 0.0;
  243.         token[t_num].l_val.v.cmplx_val.real = atof(str);
  244.     }
  245.     return(count);
  246. }
  247.  
  248.  
  249. #ifdef MSDOS
  250.  
  251. #ifdef __ZTC__
  252. substitute(char *str,int max)
  253. #else
  254. substitute()
  255. #endif
  256. {
  257.     int_error("substitution not supported by MS-DOS!",t_num);
  258. }
  259.  
  260. #else /* MSDOS */
  261. #ifdef AMIGA_LC_5_1
  262. substitute()
  263. {
  264.     int_error("substitution not supported by AmigaDOS!",t_num);
  265. }
  266.  
  267. #else /* AMIGA_LC_5_1 */
  268.  
  269. substitute(str,max)            /* substitute output from ` ` */
  270. char *str;
  271. int max;
  272. {
  273. register char *last;
  274. register int i,c;
  275. register FILE *f;
  276. #ifdef AMIGA_AC_5
  277. int fd;
  278. #else
  279. FILE *popen();
  280. #endif
  281. static char pgm[MAX_LINE_LEN+1],output[MAX_LINE_LEN+1];
  282.  
  283. #ifdef vms
  284. int chan;
  285. static $DESCRIPTOR(pgmdsc,pgm);
  286. static $DESCRIPTOR(lognamedsc,MAILBOX);
  287. #endif /* vms */
  288.  
  289.     i = 0;
  290.     last = str;
  291.     while (*(++last) != '`') {
  292.         if (*last == '\0')
  293.             int_error("unmatched `",t_num);
  294.         pgm[i++] = *last;
  295.     }
  296.     pgm[i] = '\0';        /* end with null */
  297.     max -= strlen(last);    /* max is now the max length of output sub. */
  298.   
  299. #ifdef vms
  300.       pgmdsc.dsc$w_length = i;
  301.        if (!((vaxc$errno = sys$crembx(0,&chan,0,0,0,0,&lognamedsc)) & 1))
  302.            os_error("sys$crembx failed",NO_CARET);
  303.    
  304.        if (!((vaxc$errno = lib$spawn(&pgmdsc,0,&lognamedsc,&1)) & 1))
  305.            os_error("lib$spawn failed",NO_CARET);
  306.    
  307.        if ((f = fopen(MAILBOX,"r")) == NULL)
  308.            os_error("mailbox open failed",NO_CARET);
  309. #else /* vms */
  310. #ifdef AMIGA_AC_5
  311.       if ((fd = open(pgm,"O_RDONLY")) == -1)
  312. #else
  313.       if ((f = popen(pgm,"r")) == NULL)
  314. #endif
  315.           os_error("popen failed",NO_CARET);
  316. #endif /* vms */
  317.  
  318.     i = 0;
  319.     while ((c = getc(f)) != EOF) {
  320.         output[i++] = ((c == '\n') ? ' ' : c);    /* newlines become blanks*/
  321.         if (i == max) {
  322. #ifdef AMIGA_AC_5
  323.             (void) close(fd);
  324. #else
  325.             (void) pclose(f);
  326. #endif
  327.             int_error("substitution overflow", t_num);
  328.         }
  329.     }
  330. #ifdef AMIGA_AC_5
  331.     (void) close(fd);
  332. #else
  333.     (void) pclose(f);
  334. #endif
  335.     if (i + strlen(last) > max)
  336.         int_error("substitution overflowed rest of line", t_num);
  337.     (void) strncpy(output+i,last+1,MAX_LINE_LEN-i);
  338.                                     /* tack on rest of line to output */
  339.     (void) strcpy(str,output);                /* now replace ` ` with output */
  340.     screen_ok = FALSE;
  341. }
  342. #endif /* AMIGA_LC_5_1 */
  343. #endif /* MS-DOS */
  344.